﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace ALinq.Dynamic
{
    internal partial class ExpressionParser
    {
        #region predefinedTypes
        static readonly Type[] predefinedTypes = {
                                                     typeof(Object),
                                                     typeof(Boolean),
                                                     typeof(Char),
                                                     typeof(String),
                                                     typeof(SByte),
                                                     typeof(Byte),
                                                     typeof(Int16),
                                                     typeof(UInt16),
                                                     typeof(Int32),
                                                     typeof(UInt32),
                                                     typeof(Int64),
                                                     typeof(UInt64),
                                                     typeof(Single),
                                                     typeof(Double),
                                                     typeof(Decimal),
                                                     typeof(DateTime),
                                                     typeof(TimeSpan),
                                                     typeof(Guid),
                                                     typeof(Math),
                                                     typeof(Convert)
                                                 };
        #endregion

        private ReaderWriterLock keyWordsLock = new ReaderWriterLock();

        static readonly Expression trueLiteral = Expression.Constant(true);
        static readonly Expression falseLiteral = Expression.Constant(false);
        static readonly Expression nullLiteral = Expression.Constant(null);

        private const string keywordNew = "new";
        private const string keywordIt = "it";
        private const string keywordIif = "iif";
        private const string keywordRow = "row";
        private const string keywordThis = "this";
        private const string keywordValue = "value";
        private const string keywordMultiSet = "multiset";
        private const string keywordDateteime = "DATETIME";

        private static Dictionary<string, object> keywords;
        private static Dictionary<string, object> functions;

        private Dictionary<string, object> symbols;
        IDictionary<string, object> externals;
        Dictionary<Expression, string> literals;
        protected ParameterExpression it;
        private ParameterExpression me;
        string text;
        int textPos;
        int textLen;
        char ch;
        protected Token token;
        private ModuleBuilder moduleBuilder;

        public ExpressionParser(IEnumerable<ParameterExpression> parameters, string expression, object[] values)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");



            symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            literals = new Dictionary<Expression, string>();
            CreateFunctions();

            if (parameters != null)
                ProcessParameters(parameters);

            if (values != null)
                ProcessValues(values);

            text = expression;
            textLen = text.Length;
            SetTextPos(0);
            NextToken();
        }

        private Dictionary<string, object> Keywords
        {
            get
            {
                keyWordsLock.AcquireReaderLock(-1);
                try
                {
                    if (keywords != null)
                        return keywords;
                }
                finally
                {
                    keyWordsLock.ReleaseReaderLock();
                }

                keyWordsLock.AcquireWriterLock(-1);
                try
                {
                    // keywords = CreateKeywords();
                    var d = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                    d.Add("true", trueLiteral);
                    d.Add("false", falseLiteral);
                    d.Add("null", nullLiteral);
                    d.Add(keywordIt, keywordIt);
                    d.Add(keywordIif, keywordIif);
                    d.Add(keywordNew, keywordNew);
                    d.Add(keywordRow, keywordRow);
                    d.Add(keywordThis, keywordThis);
                    d.Add(keywordValue, keywordValue);
                    d.Add(keywordMultiSet, keywordMultiSet);
                    //d.Add(keywordDateteime, keywordDateteime);

                    foreach (Type type in predefinedTypes)
                        d.Add(type.Name, type);

                    keywords = d;
                }
                finally
                {
                    keyWordsLock.ReleaseReaderLock();
                }

                return keywords;
            }
        }

        private void ProcessParameters(IEnumerable<ParameterExpression> parameters)
        {
            foreach (ParameterExpression pe in parameters)
                if (!String.IsNullOrEmpty(pe.Name))
                    AddSymbol(pe.Name, pe);

            if (parameters.Count() == 1 && String.IsNullOrEmpty(parameters.Single().Name))
                it = parameters.Single();
        }

        void ProcessValues(object[] values)
        {
            for (int i = 0; i < values.Length; i++)
            {
                object value = values[i];
                if (i == values.Length - 1 && value is IDictionary<string, object>)
                {
                    externals = (IDictionary<string, object>)value;
                }
                else
                {
                    AddSymbol("@" + i.ToString(System.Globalization.CultureInfo.InvariantCulture), value);
                }
            }
        }

        void AddSymbol(string name, object value)
        {
            if (symbols.ContainsKey(name))
                throw ParseError(Res.DuplicateIdentifier, name);
            symbols.Add(name, value);
        }

        protected virtual bool GetSymbol(string symbolName, out object value)
        {
            Debug.Assert(symbols != null);
            var result = symbols.TryGetValue(symbolName, out value);
            return result;
        }

        public Expression Parse()
        {
            return this.Parse((Type)null);
        }

        public Expression Parse(Type resultType)
        {
            int exprPos = token.Position;
            Expression expr = ParseExpression();
            if (resultType != null)
                if ((expr = PromoteExpression(expr, resultType, true)) == null)
                    throw ParseError(exprPos, Res.ExpressionTypeMismatch, GetTypeName(resultType));

            if (TokenIdentifierIs("as") || token.Identity == TokenId.Comma)
            {
                expr = this.ParseNew(expr);
            }
            ValidateToken(TokenId.End, Res.SyntaxError);
            return expr;
        }

#pragma warning disable 0219
        public IEnumerable<DynamicOrdering> ParseOrdering()
        {
            List<DynamicOrdering> orderings = new List<DynamicOrdering>();
            while (true)
            {
                Expression expr = ParseExpression();
                bool ascending = true;
                if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending"))
                {
                    NextToken();
                }
                else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending"))
                {
                    NextToken();
                    ascending = false;
                }
                orderings.Add(new DynamicOrdering { Selector = expr, Ascending = ascending });
                if (token.Identity != TokenId.Comma) break;
                NextToken();
            }
            ValidateToken(TokenId.End, Res.SyntaxError);
            return orderings;
        }
#pragma warning restore 0219

        // ?: operator
        protected virtual Expression ParseExpression()
        {
            int errorPos = token.Position;
            Expression expr = ParseLogicalOr();
            if (token.Identity == TokenId.Question)
            {
                NextToken();
                Expression expr1 = ParseExpression();
                ValidateToken(TokenId.Colon, Res.ColonExpected);
                NextToken();
                Expression expr2 = ParseExpression();
                expr = GenerateConditional(expr, expr1, expr2, errorPos);
            }



            return expr;
        }





        // ||, or operator
        Expression ParseLogicalOr()
        {
            Expression left = ParseLogicalAnd();
            while (token.Identity == TokenId.DoubleBar || TokenIdentifierIs("or"))
            {
                Token op = token;
                NextToken();
                Expression right = ParseLogicalAnd();
                CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Text, ref left, ref right, op.Position);
                left = Expression.OrElse(left, right);
            }
            return left;
        }

        // &&, and operator
        Expression ParseLogicalAnd()
        {
            Expression left = ParseComparison();
            while (token.Identity == TokenId.DoubleAmphersand || TokenIdentifierIs("and"))
            {
                Token op = token;
                NextToken();
                Expression right = ParseComparison();
                CheckAndPromoteOperands(typeof(ILogicalSignatures), op.Text, ref left, ref right, op.Position);
                left = Expression.AndAlso(left, right);
            }
            return left;
        }

        // =, ==, !=, <>, >, >=, <, <= operators
        Expression ParseComparison()
        {
            Expression left = ParseAdditive();
            while (token.Identity == TokenId.Equal || token.Identity == TokenId.DoubleEqual ||
                   token.Identity == TokenId.ExclamationEqual || token.Identity == TokenId.LessGreater ||
                   token.Identity == TokenId.GreaterThan || token.Identity == TokenId.GreaterThanEqual ||
                   token.Identity == TokenId.LessThan || token.Identity == TokenId.LessThanEqual)
            {
                Token op = token;
                NextToken();
                Expression right = ParseAdditive();
                bool isEquality = op.Identity == TokenId.Equal || op.Identity == TokenId.DoubleEqual ||
                                  op.Identity == TokenId.ExclamationEqual || op.Identity == TokenId.LessGreater;
                if (isEquality && !left.Type.IsValueType && !right.Type.IsValueType)
                {
                    if (left.Type != right.Type)
                    {
                        if (left.Type.IsAssignableFrom(right.Type))
                        {
                            right = Expression.Convert(right, left.Type);
                        }
                        else if (right.Type.IsAssignableFrom(left.Type))
                        {
                            left = Expression.Convert(left, right.Type);
                        }
                        else
                        {
                            throw IncompatibleOperandsError(op.Text, left, right, op.Position);
                        }
                    }
                }
                else if (IsEnumType(left.Type) || IsEnumType(right.Type))
                {
                    if (left.Type != right.Type)
                    {
                        Expression e;
                        if ((e = PromoteExpression(right, left.Type, true)) != null)
                        {
                            right = e;
                        }
                        else if ((e = PromoteExpression(left, right.Type, true)) != null)
                        {
                            left = e;
                        }
                        else
                        {
                            throw IncompatibleOperandsError(op.Text, left, right, op.Position);
                        }
                    }
                }
                else
                {
                    #region MyRegion
                    ////Try to change type of the value to the target type.
                    //var converted = false;
                    //try
                    //{
                    //    if (IsDateTimeType(left.Type) && right.Type == typeof(string))
                    //    {
                    //        if (right.NodeType == ExpressionType.Constant)
                    //        {
                    //            var value = Convert.ToDateTime(((ConstantExpression)right).Value);
                    //            if (IsNullableType(left.Type))
                    //            {
                    //                right = Expression.Constant(value, typeof(DateTime?));
                    //            }
                    //            else
                    //            {
                    //                right = Expression.Constant(value);
                    //            }
                    //            converted = true;
                    //        }
                    //    }
                    //    if (IsDateTimeType(right.Type) && left.Type == typeof(string))
                    //    {
                    //        if (left.NodeType == ExpressionType.Constant)
                    //        {
                    //            var value = Convert.ToDateTime(((ConstantExpression)left).Value);
                    //            left = Expression.Constant(value);
                    //            converted = true;
                    //        }
                    //    }
                    //}
                    //finally
                    //{
                    //    if (!converted)
                    //CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),
                    //    op.text, ref left, ref right, op.pos);
                    //} 
                    #endregion
                    CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures),
                                            op.Text, ref left, ref right, op.Position);
                }
                switch (op.Identity)
                {
                    case TokenId.Equal:
                    case TokenId.DoubleEqual:
                        left = GenerateEqual(left, right);
                        break;
                    case TokenId.ExclamationEqual:
                    case TokenId.LessGreater:
                        left = GenerateNotEqual(left, right);
                        break;
                    case TokenId.GreaterThan:
                        left = GenerateGreaterThan(left, right);
                        break;
                    case TokenId.GreaterThanEqual:
                        left = GenerateGreaterThanEqual(left, right);
                        break;
                    case TokenId.LessThan:
                        left = GenerateLessThan(left, right);
                        break;
                    case TokenId.LessThanEqual:
                        left = GenerateLessThanEqual(left, right);
                        break;
                }
            }
            return left;
        }

        // +, -, & operators
        Expression ParseAdditive()
        {
            Expression left = ParseMultiplicative();
            while (token.Identity == TokenId.Plus || token.Identity == TokenId.Minus ||
                   token.Identity == TokenId.Amphersand)
            {
                Token op = token;
                NextToken();
                Expression right = ParseMultiplicative();
                switch (op.Identity)
                {
                    case TokenId.Plus:
                        if (left.Type == typeof(string) || right.Type == typeof(string))
                            goto case TokenId.Amphersand;
                        CheckAndPromoteOperands(typeof(IAddSignatures), op.Text, ref left, ref right, op.Position);
                        left = GenerateAdd(left, right);
                        break;
                    case TokenId.Minus:
                        CheckAndPromoteOperands(typeof(ISubtractSignatures), op.Text, ref left, ref right, op.Position);
                        left = GenerateSubtract(left, right);
                        break;
                    case TokenId.Amphersand:
                        left = GenerateStringConcat(left, right);
                        break;
                }
            }
            return left;
        }

        // *, /, %, mod operators
        Expression ParseMultiplicative()
        {
            Expression left = ParseUnary();
            while (token.Identity == TokenId.Asterisk || token.Identity == TokenId.Slash ||
                   token.Identity == TokenId.Percent || TokenIdentifierIs("mod"))
            {
                Token op = token;
                NextToken();
                Expression right = ParseUnary();
                CheckAndPromoteOperands(typeof(IArithmeticSignatures), op.Text, ref left, ref right, op.Position);
                if (op.Is(TokenId.Asterisk))
                {
                    left = Expression.Multiply(left, right);
                }
                else if (op.Is(TokenId.Slash))
                {
                    left = Expression.Divide(left, right);
                }
                else if (op.Is(TokenId.Percent) || op.Is(TokenId.Identifier))
                {
                    left = Expression.Modulo(left, right);
                }
            }
            return left;
        }

        // -, !, not unary operators
        protected Expression ParseUnary()
        {
            if (token.Identity == TokenId.Minus || token.Identity == TokenId.Exclamation ||
                TokenIdentifierIs("not"))
            {
                Token op = token;
                NextToken();
                if (op.Identity == TokenId.Minus && (token.Identity == TokenId.IntegerLiteral ||
                                               token.Identity == TokenId.RealLiteral))
                {
                    //token.Text = "-" + token.Text;
                    //token.Position = op.Position;
                    token.SetValues(token.Identity, "-" + token.Text, op.Position);
                    return ParsePrimary();
                }
                Expression expr = ParseUnary();
                if (op.Identity == TokenId.Minus)
                {
                    CheckAndPromoteOperand(typeof(INegationSignatures), op.Text, ref expr, op.Position);
                    expr = Expression.Negate(expr);
                }
                else
                {
                    CheckAndPromoteOperand(typeof(INotSignatures), op.Text, ref expr, op.Position);
                    expr = Expression.Not(expr);
                }
                return expr;
            }

            return ParsePrimary();
        }

        protected virtual Expression ParsePrimary()
        {
            Expression expr = ParsePrimaryStart();
            while (true)
            {
                if (token.Identity == TokenId.Dot)
                {
                    NextToken();
                    expr = ParseMemberAccess(null, expr);
                }
                else if (token.Identity == TokenId.OpenBracket)
                {
                    expr = ParseElementAccess(expr);
                }
                //else if (token.Identity == TokenId.Identifier)
                //{
                //    if (TokenIdentifierIs(KEYWORD_NOT))
                //    {
                //        expr = ParseUnary();
                //    }
                //    else if (TokenIdentifierIs(KEYWORD_IN))
                //    {
                //        NextToken();
                //        var q = ParseExpression();
                //        var elementType = q.Type.GetGenericArguments()[0];
                //        expr = Expression.Call(typeof(Enumerable), "Contains", new[] { elementType }, q, expr);
                //    }
                //    else
                //    {
                //        break;
                //    }
                //}
                else
                {
                    break;
                }
            }
            return expr;
        }

        protected Expression ParsePrimaryStart()
        {
            if (token.IsIdentifier())
            {
                return ParseIdentifier();
            }
            if (token.Identity == TokenId.StringLiteral)
            {
                return ParseStringLiteral();
            }
            if (token.Identity == TokenId.Sharp)
            {
                return ParseDateTimeLiteral();
            }
            if (token.Identity == TokenId.IntegerLiteral)
            {
                return ParseIntegerLiteral();
            }
            if (token.Identity == TokenId.RealLiteral)
            {
                return ParseRealLiteral();
            }
            if (token.Identity == TokenId.OpenParen)
            {
                return ParseParenExpression();
            }
            if (token.Identity == TokenId.OpenBracket)
            {
                //var expr = Expression.Parameter(, "");
                return ParseElementAccess(this.it);
            }

            throw ParseError(Res.ExpressionExpected);
        }

        protected Expression ParseValue()
        {
            switch (token.Identity)
            {
                case TokenId.StringLiteral:
                    return ParseStringLiteral();
                case TokenId.Sharp:
                    return ParseDateTimeLiteral();
                case TokenId.IntegerLiteral:
                    return ParseIntegerLiteral();
                case TokenId.RealLiteral:
                    return ParseRealLiteral();
                default:
                    throw ParseError(Res.ExpressionExpected);
            }
        }

        Expression ParseStringLiteral()
        {
            ValidateToken(TokenId.StringLiteral);
            char quote = token.Text[0];
            string s = token.Text.Substring(1, token.Text.Length - 2);
            int start = 0;
            while (true)
            {
                int i = s.IndexOf(quote, start);
                if (i < 0) break;
                s = s.Remove(i, 1);
                start = i + 1;
            }
            /*
            if (quote == '\'')
            {
                if (s.Length != 1)
                    throw ParseError(Res.InvalidCharacterLiteral);
                NextToken();
                return CreateLiteral(s[0], s);
            }
            */
            NextToken();

            return CreateLiteral(s, s);
        }



        Expression ParseDateTimeLiteral()
        {
            ValidateToken(TokenId.Sharp);
            char quote = token.Text[0];
            string s = token.Text.Substring(1, token.Text.Length - 2);
            int start = 0;
            while (true)
            {
                int i = s.IndexOf(quote, start);
                if (i < 0) break;
                s = s.Remove(i, 1);
                start = i + 1;
            }
            NextToken();
            //TODO:验证字符串格式
            return CreateLiteral(Convert.ToDateTime(s), s);
        }


        Expression ParseIntegerLiteral()
        {
            ValidateToken(TokenId.IntegerLiteral);
            string text = token.Text;
            if (text[0] != '-')
            {
                ulong value;
                if (!UInt64.TryParse(text, out value))
                    throw ParseError(Res.InvalidIntegerLiteral, text);
                NextToken();
                if (value <= (ulong)Int32.MaxValue) return CreateLiteral((int)value, text);
                if (value <= (ulong)UInt32.MaxValue) return CreateLiteral((uint)value, text);
                if (value <= (ulong)Int64.MaxValue) return CreateLiteral((long)value, text);
                return CreateLiteral(value, text);
            }
            else
            {
                long value;
                if (!Int64.TryParse(text, out value))
                    throw ParseError(Res.InvalidIntegerLiteral, text);
                NextToken();
                if (value >= Int32.MinValue && value <= Int32.MaxValue)
                    return CreateLiteral((int)value, text);
                return CreateLiteral(value, text);
            }
        }

        Expression ParseRealLiteral()
        {
            ValidateToken(TokenId.RealLiteral);
            string text = token.Text;
            object value = null;
            char last = text[text.Length - 1];
            if (last == 'F' || last == 'f')
            {
                float f;
                if (Single.TryParse(text.Substring(0, text.Length - 1), out f)) value = f;
            }
            else
            {
                double d;
                if (Double.TryParse(text, out d)) value = d;
            }
            if (value == null) throw ParseError(Res.InvalidRealLiteral, text);
            NextToken();
            return CreateLiteral(value, text);
        }

        Expression CreateLiteral(object value, string text)
        {
            ConstantExpression expr = Expression.Constant(value);
            literals.Add(expr, text);
            return expr;
        }

        Expression ParseParenExpression()
        {
            Debug.Assert(token.Identity == TokenId.OpenParen);
            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            NextToken();
            Expression e = ParseExpression();
            ValidateToken(TokenId.CloseParen, Res.CloseParenOrOperatorExpected);
            NextToken();
            return e;
        }

        protected virtual Expression ParseIdentifier()
        {
            return ParseIdentifier(true);
        }

        protected Expression ParseIdentifier(bool throwException)
        {
            ValidateToken(TokenId.Identifier);



            object value;
            if (functions.TryGetValue(token.Text, out value))
            {
                MethodInfo method = value as MethodInfo;
                if (method != null)
                    return ParseStaticMethod(method);

                return ParseStaticMemberAccess((Type)value);
            }

            if (Keywords.TryGetValue(token.Text, out value))
            {
                if (value is Type)
                    return ParseTypeAccess((Type)value);

                if (value == (object)keywordIt)
                    return ParseIt();

                if (value == (object)keywordIif)
                    return ParseIif();

                if (value == (object)keywordNew)
                    return ParseNewObject();

                if (value == (object)keywordRow)
                    return ParseNewRow();

                if (value == (object)keywordValue)
                {
                    NextToken();

                    var expr = ParseUnary();

                    ValidateToken(TokenId.End, Res.SyntaxError);

                    return expr;
                }

                if (value == (object)keywordMultiSet)
                {
                    return ParseMultiSet();
                }

                NextToken();
                return (Expression)value;
            }
            if (GetSymbol(token.Text, out value) ||
                externals != null && externals.TryGetValue(token.Text, out value))
            {
                var expr = value as Expression;
                if (expr == null)
                {
                    expr = Expression.Constant(value);
                }
                else
                {
                    //处理方法的调用
                    var lambda = expr as LambdaExpression;
                    if (lambda != null)
                        return ParseLambdaInvocation(lambda);
                }
                NextToken();
                return expr;
            }
            if (it != null)
                return ParseMemberAccess(null, it);

            if (throwException)
                throw ParseError(Res.UnknownIdentifier, token.Text);

            return null;
        }

        protected Expression ParseIt()
        {
            if (it == null)
                throw ParseError(Res.NoItInScope);
            NextToken();
            return it;
        }

        protected Expression ParseIif()
        {
            int errorPos = token.Position;
            NextToken();
            Expression[] args = ParseArgumentList();
            if (args.Length != 3)
                throw ParseError(errorPos, Res.IifRequiresThreeArgs);
            return GenerateConditional(args[0], args[1], args[2], errorPos);
        }

        Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos)
        {
            if (test.Type != typeof(bool))
                throw ParseError(errorPos, Res.FirstExprMustBeBool);
            if (expr1.Type != expr2.Type)
            {
                Expression expr1as2 = expr2 != nullLiteral ? PromoteExpression(expr1, expr2.Type, true) : null;
                Expression expr2as1 = expr1 != nullLiteral ? PromoteExpression(expr2, expr1.Type, true) : null;
                if (expr1as2 != null && expr2as1 == null)
                {
                    expr1 = expr1as2;
                }
                else if (expr2as1 != null && expr1as2 == null)
                {
                    expr2 = expr2as1;
                }
                else
                {
                    string type1 = expr1 != nullLiteral ? expr1.Type.Name : "null";
                    string type2 = expr2 != nullLiteral ? expr2.Type.Name : "null";
                    if (expr1as2 != null && expr2as1 != null)
                        throw ParseError(errorPos, Res.BothTypesConvertToOther, type1, type2);
                    throw ParseError(errorPos, Res.NeitherTypeConvertsToOther, type1, type2);
                }
            }
            return Expression.Condition(test, expr1, expr2);
        }

        protected Expression ParseNewObject()
        {
            NextToken();

            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            NextToken();
            var expr = ParseNewInner(typeof(DynamicObject));
            ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
            NextToken();
            //ValidateToken(TokenId.End, Res.CloseParenOrCommaExpected);

            NextToken();
            return expr;
        }

        protected Expression ParseNewRow()
        {
            NextToken();

            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            NextToken();

            var expr = ParseNewInner(typeof(DynamicRow));

            ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
            NextToken();

            NextToken();

            return expr;
        }


        //1、語句：Select e.FirstName, e.LastName From Employees as e
        //將 e.FirstName, e.LastName 解釋成為表達式
        //2、語句：Select e From Employees as e
        //將 e 解釋成表達式
        protected Expression ParseNewInner(Type newObjectBaseType)
        {
            #region OldCode
            //NextToken();
            //ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            //NextToken();
            //List<DynamicProperty> properties = new List<DynamicProperty>();
            //List<Expression> expressions = new List<Expression>();
            //while (true)
            //{
            //    int exprPos = token.Position;
            //    Expression expr = ParseExpression();
            //    string propName;
            //    if (TokenIdentifierIs("as"))
            //    {
            //        NextToken();
            //        propName = GetIdentifier();
            //        NextToken();
            //    }
            //    else
            //    {
            //        MemberExpression me = expr as MemberExpression;
            //        if (me == null) throw ParseError(exprPos, Res.MissingAsClause);
            //        propName = me.Member.Name;
            //    }
            //    expressions.Add(expr);
            //    properties.Add(new DynamicProperty(propName, expr.Type));
            //    if (token.Identity != TokenId.Comma) break;
            //    NextToken();
            //}
            //ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
            //NextToken();
            //Type type = DynamicExpression.CreateClass(properties);
            //MemberBinding[] bindings = new MemberBinding[properties.Count];
            //for (int i = 0; i < bindings.Length; i++)
            //    bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
            //return Expression.MemberInit(Expression.New(type), bindings); 
            #endregion

            List<DynamicProperty> properties = new List<DynamicProperty>();
            List<Expression> expressions = new List<Expression>();

            while (true)
            {
                int exprPos = token.Position;
                Expression expr = ParseExpression();
                string propName = null;
                if (TokenIdentifierIs("as"))
                {
                    NextToken();
                    propName = GetIdentifier();
                    NextToken();
                }
                else
                {
                    if (expr.NodeType == ExpressionType.MemberAccess)
                    {
                        propName = ((MemberExpression)expr).Member.Name;
                    }
                    else if (expr.NodeType == ExpressionType.Call)
                    {
                        var call = ((MethodCallExpression)expr);
                        if (call.Method.Name == "get_Item" && call.Arguments.Count == 1)
                        {
                            if (call.Arguments[0].NodeType == ExpressionType.Constant)
                            {
                                propName = ((ConstantExpression)call.Arguments[0]).Value.ToString();
                            }
                        }
                    }
                    else if (expr.NodeType == ExpressionType.Parameter)
                    {
                        propName = ((ParameterExpression)expr).Name;
                    }


                    if (propName == null)
                        throw ParseError(exprPos, Res.MissingAsClause);
                }
                expressions.Add(expr);
                properties.Add(new DynamicProperty(propName, expr.Type));
                if (token.Identity != TokenId.Comma) break;
                NextToken();
            }



            Type objectType = DynamicExpression.CreateClass(properties, newObjectBaseType);
            MemberBinding[] bindings = new MemberBinding[properties.Count];
            for (int i = 0; i < bindings.Length; i++)
                bindings[i] = Expression.Bind(objectType.GetProperty(properties[i].Name), expressions[i]);
            return Expression.MemberInit(Expression.New(objectType), bindings);
        }

        /// <summary>
        /// 主要用于将如下字符串解释成 New 对象。 
        /// 1、FirstName as F
        /// 2、FirstName as F, LastName as L
        /// 3、[FirstName] as F, [LastName] as L，其它“[”、“]”表示使用索引器。
        /// </summary>
        /// <param name="startExpression"></param>
        /// <returns></returns>
        Expression ParseNew(Expression startExpression)
        {
            if (startExpression == null)
                throw new ArgumentNullException("startExpression");
            //NextToken();
            //ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            //NextToken();
            List<DynamicProperty> properties = new List<DynamicProperty>();
            List<Expression> expressions = new List<Expression>();
            //expressions.Add(startExpression);
            while (true)
            {
                Expression expr;
                if (expressions.Count == 0)
                    expr = startExpression;
                else
                    expr = ParseExpression();

                string propName = null;
                if (TokenIdentifierIs("as"))
                {
                    NextToken();
                    propName = GetIdentifier();
                    NextToken();
                }
                else
                {
                    if (expr.NodeType == ExpressionType.MemberAccess)
                    {
                        propName = ((MemberExpression)expr).Member.Name;
                    }
                    else if (expr.NodeType == ExpressionType.Call)
                    {
                        var call = ((MethodCallExpression)expr);
                        if (call.Method.Name == "get_Item" && call.Arguments.Count == 1)
                        {
                            if (call.Arguments[0].NodeType == ExpressionType.Constant)
                            {
                                propName = ((ConstantExpression)call.Arguments[0]).Value.ToString();
                            }
                        }
                    }
                }
                expressions.Add(expr);
                properties.Add(new DynamicProperty(propName, expr.Type));
                if (token.Identity != TokenId.Comma) break;
                NextToken();
            }

            Type type = DynamicExpression.CreateClass(properties, typeof(DynamicRow));
            MemberBinding[] bindings = new MemberBinding[properties.Count];
            for (int i = 0; i < bindings.Length; i++)
                bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]);
            return Expression.MemberInit(Expression.New(type), bindings);
        }

        Expression ParseLambdaInvocation(LambdaExpression lambda)
        {
            int errorPos = token.Position;
            NextToken();
            Expression[] args = ParseArgumentList();
            MethodBase method;
            if (FindMethod(lambda.Type, "Invoke", false, args, out method) != 1)
                throw ParseError(errorPos, Res.ArgsIncompatibleWithLambda);
            return Expression.Invoke(lambda, args);
        }

        protected Expression ParseTypeAccess(Type type)
        {
            int errorPos = token.Position;
            NextToken();
            if (token.Identity == TokenId.Question)
            {
                if (!type.IsValueType || IsNullableType(type))
                    throw ParseError(errorPos, Res.TypeHasNoNullableForm, GetTypeName(type));
                type = typeof(Nullable<>).MakeGenericType(type);
                NextToken();
            }
            if (token.Identity == TokenId.OpenParen)
            {
                Expression[] args = ParseArgumentList();
                MethodBase method;
                switch (FindBestMethod(type.GetConstructors(), args, out method))
                {
                    case 0:
                        if (args.Length == 1)
                            return GenerateConversion(args[0], type, errorPos);
                        throw ParseError(errorPos, Res.NoMatchingConstructor, GetTypeName(type));
                    case 1:
                        return Expression.New((ConstructorInfo)method, args);
                    default:
                        throw ParseError(errorPos, Res.AmbiguousConstructorInvocation, GetTypeName(type));
                }
            }
            if (token.Identity == TokenId.OpenBracket)
            {
                NextToken();
                var items = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type)); //new List<string>();
                if (token.Identity != TokenId.CloseBracket)
                {
                    while (true)
                    {
                        var s = (ConstantExpression)ParseValue();

                        items.Add(s.Value);
                        if (token.Identity != TokenId.Comma) break;
                        NextToken();
                    }
                }
                ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected);
                NextToken();
                return Expression.Constant(items);

            }

            if (token.Identity == TokenId.StringLiteral)
            {
                Expression expr = ParseUnary();
                expr = Expression.Call(typeof(Convert).GetMethod("ToDateTime", new[] { expr.Type }), expr);//(null, typeof(Convert).GetMember("ToDateTime")[0]);
                //expr = Expression.Lambda(ma,Expression);
                return expr;
            }

            if (token.Identity == TokenId.CloseParen)
            {
                NextToken();
                var expr = ParseUnary();
                expr = Expression.Convert(expr, type);
                return expr;
            }
            ValidateToken(TokenId.Dot, Res.DotOrOpenParenExpected);
            NextToken();

            return ParseStaticMemberAccess(type);
        }

        Expression GenerateConversion(Expression expr, Type type, int errorPos)
        {
            Type exprType = expr.Type;
            if (exprType == type) return expr;
            if (exprType.IsValueType && type.IsValueType)
            {
                if ((IsNullableType(exprType) || IsNullableType(type)) &&
                    GetNonNullableType(exprType) == GetNonNullableType(type))
                    return Expression.Convert(expr, type);
                if ((IsNumericType(exprType) || IsEnumType(exprType)) &&
                    (IsNumericType(type)) || IsEnumType(type))
                    return Expression.ConvertChecked(expr, type);
            }
            if (exprType.IsAssignableFrom(type) || type.IsAssignableFrom(exprType) ||
                exprType.IsInterface || type.IsInterface)
                return Expression.Convert(expr, type);
            throw ParseError(errorPos, Res.CannotConvertValue,
                             GetTypeName(exprType), GetTypeName(type));
        }


        Expression ParseStaticMethod(MethodInfo method)
        {
            Debug.Assert(method.ReturnType != typeof(void));

            NextToken();
            if (token.Identity != TokenId.OpenParen)
                throw ParseError(Res.TokenExpected, TokenId.OpenParen);

            Expression[] args = ParseArgumentList();


            var parameters = method.GetParameters();
            if (parameters.Length != args.Length)
                throw ParseError(Res.NoMatchingMethod, method.Name);

            return Expression.Call(null, method, args);
        }

        Expression ParseStaticMemberAccess(Type type)
        {
            //instance = null;
            //if (instance != null) 
            //    type = instance.Type;

            int errorPos = token.Position;
            string id = GetIdentifier();
            NextToken();
            if (token.Identity != TokenId.OpenParen)
            {
                throw ParseError(Res.TokenExpected, TokenId.OpenParen);
            }

            Expression[] args = ParseArgumentList();
            MethodBase mb;

            var methodsCount = FindMethod(type, id, true, args, out mb);
            switch (methodsCount)
            {
                case 0:
                    throw ParseError(errorPos, Res.NoApplicableMethod, id, GetTypeName(type));
                case 1:
                    MethodInfo method = (MethodInfo)mb;
                    /*
                    if (!IsPredefinedType(method.DeclaringType))
                        throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
                    */

                    if (method.ReturnType == typeof(void))
                        throw ParseError(errorPos, Res.MethodIsVoid, id, GetTypeName(method.DeclaringType));



                    return Expression.Call(null, (MethodInfo)method, args);
                default:
                    throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
                                     id, GetTypeName(type));
            }


        }

        protected Expression ParseMemberAccess(Type type, Expression instance)
        {
            if (instance != null)
                type = instance.Type;

            int errorPos = token.Position;
            string id = GetIdentifier();
            NextToken();
            if (token.Identity == TokenId.OpenParen)
            {
                //调试了 N 久，还是没有办法使用 Queryable 中的方法来调用。
                //if (method.IsStatic)
                //    return Expression.Call(typeof(Queryable), id, new[] { typeof(string) }, new[] { instance }.Union(args).ToArray());
                //HACK:由于数组中没有 Contains 方法，使用 []{'AAA','BBB','CCC'}.Contains(Name) 会出错，必须先转换成List，用着先。
                if (type.IsArray && instance.NodeType == ExpressionType.Constant && id == "Contains")
                {
                    var n = (ConstantExpression)instance;
                    Debug.Assert(n.Value != null);

                    var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(type.GetElementType()));
                    foreach (var item in (IEnumerable)n.Value)
                        list.Add(item);

                    instance = Expression.Constant(list);
                    type = list.GetType();
                }
                //=======================================================================================

                Expression[] args = ParseArgumentList();
                MethodBase mb;

                var methodsCount = FindMethod(type, id, instance == null, args, out mb);
                switch (methodsCount)
                {
                    case 0:
                        throw ParseError(errorPos, Res.NoApplicableMethod, id, GetTypeName(type));
                    case 1:
                        MethodInfo method = (MethodInfo)mb;
                        /*
                        if (!IsPredefinedType(method.DeclaringType))
                            throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
                        */

                        if (method.ReturnType == typeof(void))
                            throw ParseError(errorPos, Res.MethodIsVoid, id, GetTypeName(method.DeclaringType));



                        return Expression.Call(instance, (MethodInfo)method, args);
                    default:
                        throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
                                         id, GetTypeName(type));
                }
            }
            else
            {
                if (id == keywordThis)
                {
                    return instance;
                }
                else
                {
                    MemberInfo member = FindPropertyOrField(type, id, instance == null);
                    if (member == null)
                        throw ParseError(errorPos, Res.UnknownPropertyOrField, id, GetTypeName(type));

                    //return member is PropertyInfo ? Expression.Property(instance, (PropertyInfo)member) : Expression.Field(instance, (FieldInfo)member);
                    Debug.Assert(instance != null);
                    return Expression.MakeMemberAccess(instance, member);
                }

            }
        }

        static Type FindGenericType(Type generic, Type type)
        {
            while (type != null && type != typeof(object))
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == generic) return type;
                if (generic.IsInterface)
                {
                    foreach (Type intfType in type.GetInterfaces())
                    {
                        Type found = FindGenericType(generic, intfType);
                        if (found != null) return found;
                    }
                }
                type = type.BaseType;
            }
            return null;
        }

        Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
        {
            ParameterExpression outerIt = it;
            ParameterExpression innerIt = Expression.Parameter(elementType, "");
            it = innerIt;
            Expression[] args = ParseArgumentList();
            it = outerIt;
            MethodBase signature;
            if (FindMethod(typeof(IEnumerableSignatures), methodName, false, args, out signature) != 1)
                throw ParseError(errorPos, Res.NoApplicableAggregate, methodName);
            Type[] typeArgs;
            if (signature.Name == "Min" || signature.Name == "Max")
            {
                typeArgs = new Type[] { elementType, args[0].Type };
            }
            else
            {
                typeArgs = new Type[] { elementType };
            }
            if (args.Length == 0)
            {
                args = new Expression[] { instance };
            }
            else
            {
                args = new Expression[] { instance, Expression.Lambda(args[0], innerIt) };
            }
            return Expression.Call(typeof(Enumerable), signature.Name, typeArgs, args);
        }

        Expression[] ParseArgumentList()
        {
            ValidateToken(TokenId.OpenParen, Res.OpenParenExpected);
            NextToken();
            Expression[] args = token.Identity != TokenId.CloseParen ? ParseArguments() : new Expression[0];
            ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
            NextToken();
            return args;
        }

        Expression[] ParseArguments()
        {
            List<Expression> argList = new List<Expression>();
            while (true)
            {
                argList.Add(ParseExpression());
                if (token.Identity != TokenId.Comma) break;
                NextToken();
            }
            return argList.ToArray();
        }

        protected Expression ParseElementAccess(Expression expr)
        {
            int errorPos = token.Position;
            ValidateToken(TokenId.OpenBracket, Res.OpenParenExpected);
            NextToken();
            Expression[] args;
            if (this.token.Is(TokenId.Identifier) && token.Text != keywordThis)
            {
                args = new[] { Expression.Constant(token.Text) };
                NextToken();
            }
            else
                args = ParseArguments();

            ValidateToken(TokenId.CloseBracket, Res.CloseBracketOrCommaExpected);
            NextToken();
            if (expr.Type.IsArray)
            {
                if (expr.Type.GetArrayRank() != 1 || args.Length != 1)
                    throw ParseError(errorPos, Res.CannotIndexMultiDimArray);
                Expression index = PromoteExpression(args[0], typeof(int), true);
                if (index == null)
                    throw ParseError(errorPos, Res.InvalidIndex);
                return Expression.ArrayIndex(expr, index);
            }
            else
            {
                MethodBase mb;
                switch (FindIndexer(expr.Type, args, out mb))
                {
                    case 0:
                        throw ParseError(errorPos, Res.NoApplicableIndexer,
                                         GetTypeName(expr.Type));
                    case 1:
                        return Expression.Call(expr, (MethodInfo)mb, args);
                    default:
                        throw ParseError(errorPos, Res.AmbiguousIndexerInvocation,
                                         GetTypeName(expr.Type));
                }
            }
        }

        static bool IsPredefinedType(Type type)
        {
            foreach (Type t in predefinedTypes) if (t == type) return true;
            return false;
        }

        static bool IsNullableType(Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        }

        static Type GetNonNullableType(Type type)
        {
            return IsNullableType(type) ? type.GetGenericArguments()[0] : type;
        }

        static string GetTypeName(Type type)
        {
            Type baseType = GetNonNullableType(type);
            string s = baseType.Name;
            if (type != baseType) s += '?';
            return s;
        }

        static bool IsNumericType(Type type)
        {
            return GetNumericTypeKind(type) != 0;
        }

        static bool IsSignedIntegralType(Type type)
        {
            return GetNumericTypeKind(type) == 2;
        }

        static bool IsUnsignedIntegralType(Type type)
        {
            return GetNumericTypeKind(type) == 3;
        }

        static int GetNumericTypeKind(Type type)
        {
            type = GetNonNullableType(type);
            if (type.IsEnum) return 0;
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Char:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                    return 1;
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                    return 2;
                case TypeCode.Byte:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                    return 3;
                default:
                    return 0;
            }
        }

        static bool IsEnumType(Type type)
        {
            return GetNonNullableType(type).IsEnum;
        }

        static bool IsDateTimeType(Type type)
        {
            return GetNonNullableType(type) == typeof(DateTime);
        }

        void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos)
        {
            Expression[] args = new Expression[] { expr };
            MethodBase method;
            if (FindMethod(signatures, "F", false, args, out method) != 1)
                throw ParseError(errorPos, Res.IncompatibleOperand,
                                 opName, GetTypeName(args[0].Type));
            expr = args[0];
        }

        void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos)
        {
            Expression[] args = new Expression[] { left, right };
            MethodBase method;
            if (FindMethod(signatures, "F", false, args, out method) != 1)
                throw IncompatibleOperandsError(opName, left, right, errorPos);
            left = args[0];
            right = args[1];
        }

        Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos)
        {
            return ParseError(pos, Res.IncompatibleOperands,
                              opName, GetTypeName(left.Type), GetTypeName(right.Type));
        }

        protected MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess)
        {
            BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
                                 (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
            foreach (Type t in SelfAndBaseTypes(type))
            {
                MemberInfo[] members = t.FindMembers(MemberTypes.Property | MemberTypes.Field,
                                                     flags, Type.FilterNameIgnoreCase, memberName);
                if (members.Length != 0) return members[0];
            }
            return null;
        }

        int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method)
        {
            BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly |
                                 (staticAccess ? BindingFlags.Static : BindingFlags.Instance);
            foreach (Type t in SelfAndBaseTypes(type))
            {
                MemberInfo[] members = t.FindMembers(MemberTypes.Method,
                                                     flags, Type.FilterNameIgnoreCase, methodName);

                int count = FindBestMethod(members.Cast<MethodBase>(), args, out method);

                //var methods = type.GetMethods().Where(o => o.Name == methodName);

                if (count != 0) return count;
            }

            //var bf = BindingFlags.Static | BindingFlags.Public;
            //method = typeof(Queryable).GetMethods(bf)
            //                          .Where(o => o.Name == methodName)
            //                          .FirstOrDefault(o => o.GetParameters().Length == args.Length + 1);
            //if (method != null)
            //    return 1;

            method = null;
            return 0;
        }

        int FindIndexer(Type type, Expression[] args, out MethodBase method)
        {
            foreach (Type t in SelfAndBaseTypes(type))
            {
                MemberInfo[] members = t.GetMembers();//t.GetDefaultMembers();
                if (members.Length != 0)
                {
                    IEnumerable<MethodBase> methods = members.
                        OfType<PropertyInfo>().
                        Select(p => (MethodBase)p.GetGetMethod()).
                        Where(m => m != null);
                    int count = FindBestMethod(methods, args, out method);
                    if (count != 0) return count;
                }
            }
            method = null;
            return 0;
        }

        static IEnumerable<Type> SelfAndBaseTypes(Type type)
        {
            if (type.IsInterface)
            {
                List<Type> types = new List<Type>();
                AddInterface(types, type);
                return types;
            }
            return SelfAndBaseClasses(type);
        }

        static IEnumerable<Type> SelfAndBaseClasses(Type type)
        {
            while (type != null)
            {
                yield return type;
                type = type.BaseType;
            }
        }

        static void AddInterface(List<Type> types, Type type)
        {
            if (!types.Contains(type))
            {
                types.Add(type);
                foreach (Type t in type.GetInterfaces()) AddInterface(types, t);
            }
        }

        class MethodData
        {
            public MethodBase MethodBase;
            public ParameterInfo[] Parameters;
            public Expression[] Args;
        }

        int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method)
        {
            MethodData[] applicable = methods.
                Select(m => new MethodData { MethodBase = m, Parameters = m.GetParameters() }).
                Where(m => IsApplicable(m, args)).
                ToArray();
            if (applicable.Length > 1)
            {
                applicable = applicable.
                    Where(m => applicable.All(n => m == n || IsBetterThan(args, m, n))).
                    ToArray();
            }
            if (applicable.Length == 1)
            {
                MethodData md = applicable[0];
                for (int i = 0; i < args.Length; i++) args[i] = md.Args[i];
                method = md.MethodBase;
            }
            else
            {
                method = null;
            }
            return applicable.Length;
        }

        bool IsApplicable(MethodData method, Expression[] args)
        {
            if (method.Parameters.Length != args.Length) return false;
            Expression[] promotedArgs = new Expression[args.Length];
            for (int i = 0; i < args.Length; i++)
            {
                ParameterInfo pi = method.Parameters[i];
                if (pi.IsOut) return false;
                Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
                if (promoted == null) return false;
                promotedArgs[i] = promoted;
            }
            method.Args = promotedArgs;
            return true;
        }

        Expression PromoteExpression(Expression expr, Type type, bool exact)
        {
            if (expr.Type == type) return expr;
            if (expr is ConstantExpression)
            {
                ConstantExpression ce = (ConstantExpression)expr;
                if (ce == nullLiteral)
                {
                    if (!type.IsValueType || IsNullableType(type))
                        return Expression.Constant(null, type);
                }
                else
                {
                    string text;
                    if (literals.TryGetValue(ce, out text))
                    {
                        Type target = GetNonNullableType(type);
                        Object value = null;
                        switch (Type.GetTypeCode(ce.Type))
                        {
                            case TypeCode.Int32:
                            case TypeCode.UInt32:
                            case TypeCode.Int64:
                            case TypeCode.UInt64:
                                value = ParseNumber(text, target);
                                break;
                            case TypeCode.Double:
                                if (target == typeof(decimal)) value = ParseNumber(text, target);
                                break;
                            case TypeCode.String:
                                value = ParseEnum(text, target);
                                break;
                        }
                        if (value != null)
                            return Expression.Constant(value, type);
                    }
                }
            }
            if (IsCompatibleWith(expr.Type, type))
            {
                if (type.IsValueType || exact) return Expression.Convert(expr, type);
                return expr;
            }
            return null;
        }

        static object ParseNumber(string text, Type type)
        {
            switch (Type.GetTypeCode(GetNonNullableType(type)))
            {
                case TypeCode.SByte:
                    sbyte sb;
                    if (sbyte.TryParse(text, out sb)) return sb;
                    break;
                case TypeCode.Byte:
                    byte b;
                    if (byte.TryParse(text, out b)) return b;
                    break;
                case TypeCode.Int16:
                    short s;
                    if (short.TryParse(text, out s)) return s;
                    break;
                case TypeCode.UInt16:
                    ushort us;
                    if (ushort.TryParse(text, out us)) return us;
                    break;
                case TypeCode.Int32:
                    int i;
                    if (int.TryParse(text, out i)) return i;
                    break;
                case TypeCode.UInt32:
                    uint ui;
                    if (uint.TryParse(text, out ui)) return ui;
                    break;
                case TypeCode.Int64:
                    long l;
                    if (long.TryParse(text, out l)) return l;
                    break;
                case TypeCode.UInt64:
                    ulong ul;
                    if (ulong.TryParse(text, out ul)) return ul;
                    break;
                case TypeCode.Single:
                    float f;
                    if (float.TryParse(text, out f)) return f;
                    break;
                case TypeCode.Double:
                    double d;
                    if (double.TryParse(text, out d)) return d;
                    break;
                case TypeCode.Decimal:
                    decimal e;
                    if (decimal.TryParse(text, out e)) return e;
                    break;
            }
            return null;
        }

        static object ParseEnum(string name, Type type)
        {
            if (type.IsEnum)
            {
                MemberInfo[] memberInfos = type.FindMembers(MemberTypes.Field,
                                                            BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static,
                                                            Type.FilterNameIgnoreCase, name);
                if (memberInfos.Length != 0) return ((FieldInfo)memberInfos[0]).GetValue(null);
            }
            return null;
        }

        static bool IsCompatibleWith(Type source, Type target)
        {
            if (source == target) return true;
            if (!target.IsValueType) return target.IsAssignableFrom(source);
            Type st = GetNonNullableType(source);
            Type tt = GetNonNullableType(target);
            if (st != source && tt == target) return false;
            TypeCode sc = st.IsEnum ? TypeCode.Object : Type.GetTypeCode(st);
            TypeCode tc = tt.IsEnum ? TypeCode.Object : Type.GetTypeCode(tt);
            switch (sc)
            {
                case TypeCode.SByte:
                    switch (tc)
                    {
                        case TypeCode.SByte:
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.Byte:
                    switch (tc)
                    {
                        case TypeCode.Byte:
                        case TypeCode.Int16:
                        case TypeCode.UInt16:
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.Int16:
                    switch (tc)
                    {
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.UInt16:
                    switch (tc)
                    {
                        case TypeCode.UInt16:
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.Int32:
                    switch (tc)
                    {
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.UInt32:
                    switch (tc)
                    {
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.Int64:
                    switch (tc)
                    {
                        case TypeCode.Int64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.UInt64:
                    switch (tc)
                    {
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    }
                    break;
                case TypeCode.Single:
                    switch (tc)
                    {
                        case TypeCode.Single:
                        case TypeCode.Double:
                            return true;
                    }
                    break;
                default:
                    if (st == tt) return true;
                    break;
            }
            return false;
        }

        static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2)
        {
            bool better = false;
            for (int i = 0; i < args.Length; i++)
            {
                int c = CompareConversions(args[i].Type,
                                           m1.Parameters[i].ParameterType,
                                           m2.Parameters[i].ParameterType);
                if (c < 0) return false;
                if (c > 0) better = true;
            }
            return better;
        }

        // Return 1 if s -> t1 is a better conversion than s -> t2
        // Return -1 if s -> t2 is a better conversion than s -> t1
        // Return 0 if neither conversion is better
        static int CompareConversions(Type s, Type t1, Type t2)
        {
            if (t1 == t2) return 0;
            if (s == t1) return 1;
            if (s == t2) return -1;
            bool t1t2 = IsCompatibleWith(t1, t2);
            bool t2t1 = IsCompatibleWith(t2, t1);
            if (t1t2 && !t2t1) return 1;
            if (t2t1 && !t1t2) return -1;
            if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) return 1;
            if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) return -1;
            return 0;
        }

        Expression GenerateEqual(Expression left, Expression right)
        {
            return Expression.Equal(left, right);
        }

        Expression GenerateNotEqual(Expression left, Expression right)
        {
            return Expression.NotEqual(left, right);
        }

        Expression GenerateGreaterThan(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.GreaterThan(
                    GenerateStaticMethodCall("Compare", left, right),
                    Expression.Constant(0)
                    );
            }
            return Expression.GreaterThan(left, right);
        }

        Expression GenerateGreaterThanEqual(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.GreaterThanOrEqual(
                    GenerateStaticMethodCall("Compare", left, right),
                    Expression.Constant(0)
                    );
            }
            return Expression.GreaterThanOrEqual(left, right);
        }

        Expression GenerateLessThan(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.LessThan(
                    GenerateStaticMethodCall("Compare", left, right),
                    Expression.Constant(0)
                    );
            }
            return Expression.LessThan(left, right);
        }

        Expression GenerateLessThanEqual(Expression left, Expression right)
        {
            if (left.Type == typeof(string))
            {
                return Expression.LessThanOrEqual(
                    GenerateStaticMethodCall("Compare", left, right),
                    Expression.Constant(0)
                    );
            }
            return Expression.LessThanOrEqual(left, right);
        }

        Expression GenerateAdd(Expression left, Expression right)
        {

            if (left.Type == typeof(string) && right.Type == typeof(string))
            {
                return GenerateStaticMethodCall("Concat", left, right);
            }
            return Expression.Add(left, right);
        }

        Expression GenerateSubtract(Expression left, Expression right)
        {
            return Expression.Subtract(left, right);
        }

        Expression GenerateStringConcat(Expression left, Expression right)
        {
            return Expression.Call(
                null,
                typeof(string).GetMethod("Concat", new[] { typeof(object), typeof(object) }),
                new[] { left, right });
        }

        MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
        {
            return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
        }

        Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)
        {
            return Expression.Call(null, GetStaticMethod(methodName, left, right), new[] { left, right });
        }

        protected void SetTextPos(int pos)
        {
            Debug.Assert(pos >= 0);
            textPos = pos;
            ch = (textPos < textLen) ? text[textPos] : '\0';
        }

        void NextChar()
        {
            if (textPos < textLen) textPos++;
            ch = textPos < textLen ? text[textPos] : '\0';
        }

        protected virtual void NextToken()
        {
            while (Char.IsWhiteSpace(ch)) NextChar();
            TokenId t;
            int tokenPos = textPos;
            switch (ch)
            {
                case '!':
                    NextChar();
                    if (ch == '=')
                    {
                        NextChar();
                        t = TokenId.ExclamationEqual;
                    }
                    else
                    {
                        t = TokenId.Exclamation;
                    }
                    break;
                case '%':
                    NextChar();
                    t = TokenId.Percent;
                    break;
                case '&':
                    NextChar();
                    if (ch == '&')
                    {
                        NextChar();
                        t = TokenId.DoubleAmphersand;
                    }
                    else
                    {
                        t = TokenId.Amphersand;
                    }
                    break;
                case '(':
                    NextChar();
                    t = TokenId.OpenParen;
                    break;
                case ')':
                    NextChar();
                    t = TokenId.CloseParen;
                    break;
                case '*':
                    NextChar();
                    t = TokenId.Asterisk;
                    break;
                case '+':
                    NextChar();
                    t = TokenId.Plus;
                    break;
                case ',':
                    NextChar();
                    t = TokenId.Comma;
                    break;
                case ';':
                    NextChar();
                    t = TokenId.Semicolon;
                    break;
                case '-':
                    NextChar();
                    if (ch == '-')
                    {
                        do
                        {
                            NextChar();
                        } while (ch != '\n' && textPos < textLen);
                        t = TokenId.Comment;
                    }
                    else
                    {
                        t = TokenId.Minus;
                    }
                    break;
                case '.':
                    NextChar();
                    t = TokenId.Dot;
                    break;
                case '/':
                    NextChar();
                    t = TokenId.Slash;
                    break;
                case ':':
                    NextChar();
                    t = TokenId.Colon;
                    break;
                case '<':
                    NextChar();
                    if (ch == '=')
                    {
                        NextChar();
                        t = TokenId.LessThanEqual;
                    }
                    else if (ch == '>')
                    {
                        NextChar();
                        t = TokenId.LessGreater;
                    }
                    else
                    {
                        t = TokenId.LessThan;
                    }
                    break;
                case '=':
                    NextChar();
                    if (ch == '=')
                    {
                        NextChar();
                        t = TokenId.DoubleEqual;
                    }
                    else
                    {
                        t = TokenId.Equal;
                    }
                    break;
                case '>':
                    NextChar();
                    if (ch == '=')
                    {
                        NextChar();
                        t = TokenId.GreaterThanEqual;
                    }
                    else
                    {
                        t = TokenId.GreaterThan;
                    }
                    break;
                case '?':
                    NextChar();
                    t = TokenId.Question;
                    break;
                case '[':
                    NextChar();
                    t = TokenId.OpenBracket;
                    break;
                case ']':
                    NextChar();
                    t = TokenId.CloseBracket;
                    break;
                case '|':
                    NextChar();
                    if (ch == '|')
                    {
                        NextChar();
                        t = TokenId.DoubleBar;
                    }
                    else
                    {
                        t = TokenId.Bar;
                    }
                    break;
                case '"':
                case '\'':
                    char quote = ch;
                    do
                    {
                        NextChar();
                        while (textPos < textLen && ch != quote) NextChar();
                        if (textPos == textLen)
                            throw ParseError(textPos, Res.UnterminatedStringLiteral);
                        NextChar();
                    } while (ch == quote);
                    t = TokenId.StringLiteral;
                    break;
                case '#':
                    char sharp = ch;
                    do
                    {
                        NextChar();
                        while (textPos < textLen && ch != sharp) NextChar();
                        if (textPos == textLen)
                            throw ParseError(textPos, Res.UnterminatedStringLiteral);
                        NextChar();
                    } while (ch == sharp);
                    t = TokenId.Sharp;
                    break;
                case '{':
                    NextChar();
                    t = TokenId.OpenCurlyBrace;
                    break;
                case '}':
                    NextChar();
                    t = TokenId.CloseCurlyBrace;
                    break;
                default:
                    if (Char.IsLetter(ch) || ch == '@' || ch == '_')
                    {
                        do
                        {
                            NextChar();
                        } while (Char.IsLetterOrDigit(ch) || ch == '_');
                        t = TokenId.Identifier;
                        break;
                    }
                    if (Char.IsDigit(ch))
                    {
                        t = TokenId.IntegerLiteral;
                        do
                        {
                            NextChar();
                        } while (Char.IsDigit(ch));
                        if (ch == '.')
                        {
                            t = TokenId.RealLiteral;
                            NextChar();
                            ValidateDigit();
                            do
                            {
                                NextChar();
                            } while (Char.IsDigit(ch));
                        }
                        if (ch == 'E' || ch == 'e')
                        {
                            t = TokenId.RealLiteral;
                            NextChar();
                            if (ch == '+' || ch == '-') NextChar();
                            ValidateDigit();
                            do
                            {
                                NextChar();
                            } while (Char.IsDigit(ch));
                        }
                        if (ch == 'F' || ch == 'f') NextChar();
                        break;
                    }
                    if (textPos == textLen)
                    {
                        t = TokenId.End;
                        break;
                    }
                    throw ParseError(textPos, Res.InvalidCharacter, ch);
            }
            //token.Identity = t;
            //token.Text = text.Substring(tokenPos, textPos - tokenPos);
            //token.Position = tokenPos;
            token.SetValues(t, text.Substring(tokenPos, textPos - tokenPos), tokenPos);

            //if (token.Identity == TokenId.Comment)
            //    return NextToken();

            //return token;
        }

        protected bool TokenIdentifierIs(string id)
        {
            return (token.IsIdentifier())
                     && String.Equals(id, token.Text, StringComparison.OrdinalIgnoreCase);
        }

        string GetIdentifier()
        {
            ValidateToken(TokenId.Identifier, Res.IdentifierExpected);
            string id = token.Text;
            if (id.Length > 1 && id[0] == '@') id = id.Substring(1);
            return id;
        }

        void ValidateDigit()
        {
            if (!Char.IsDigit(ch)) throw ParseError(textPos, Res.DigitExpected);
        }

        protected void ValidateToken(TokenId t, string errorMessage)
        {
            if (!token.Is(t))
                throw ParseError(errorMessage);
        }

        protected void ValidateToken(TokenId t)
        {
            if (!token.Is(t))
                throw ParseError(Res.SyntaxError);
        }

        protected Exception ParseError(string format, params object[] args)
        {
            return ParseError(token.Position, format, args);
        }

        Exception ParseError(int pos, string format, params object[] args)
        {
            return new ParseException(string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args), pos);
        }

        static void CreateFunctions()
        {
            if (functions == null)
            {
                functions = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

                var bf = BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod;
                var concat = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) });
                functions.Add(concat.Name, concat);

                //var abs = typeof(Math).GetMethod("Abs");
                functions.Add("ABS", typeof(Math));
                functions.Add("ACOS", typeof(Math));
                functions.Add("ASIN", typeof(Math));
                functions.Add("ATAN", typeof(Math));
                functions.Add("ATN2", typeof(Math));
                functions.Add("CEILING", typeof(Math));
                functions.Add("COS", typeof(Math));
                functions.Add("COT", typeof(Math));
                //functions.Add("DEGREES"); //TODO: 沒有對應的函數
                functions.Add("EXP", typeof(Math));
                functions.Add("FLOOR", typeof(Math));
                functions.Add("LOG", typeof(Math));
                functions.Add("LOG10", typeof(Math));
                functions.Add("PI", typeof(Math));
                functions.Add("POWER", new KeyValuePair<string, object>("POW", typeof(Math)));
                //RADIANS //TODO: 沒有對應的函數
                //functions.Add("RAND", typeof (Math));//TODO: 沒有對應的函數

            }

            return;
        }

        private const string KEYWORD_VALUE = "VALUE";
        private const string KEYWORD_NEW = "NEW";
        private const string KEYWORD_ROW = "ROW";
        /// <summary>
        /// 用于解释形如 FirstName = 'AAA', LastName = 'BBB' 为 New 表达式
        /// </summary>
        /// <returns></returns>
        protected Expression ParseNewEntity()
        {
            Expression exprSelection;
            switch (token.Text.ToUpper())
            {
                case KEYWORD_VALUE:
                    NextToken();
                    exprSelection = this.ParseExpression();
                    //if (token.Identity != TokenId.End)
                    //    throw ParseError(Res.SyntaxError);

                    break;

                case KEYWORD_NEW:
                    exprSelection = this.ParseNewObject();
                    //if (token.Identity != TokenId.End)
                    //    throw ParseError(Res.SyntaxError);


                    break;

                case KEYWORD_ROW:
                    exprSelection = ParseNewRow();
                    //if (token.Identity != TokenId.End)
                    //    throw ParseError(Res.SyntaxError);
                    break;


                default:
                    exprSelection = ParseNewInner(typeof(DynamicRow));
                    //if (token.Identity != TokenId.End)
                    //    throw ParseError(Res.SyntaxError);

                    break;
            }
            return exprSelection;

        }

        private Type CreateEntityType(string[] names, Type[] types)
        {
            Debug.Assert(names.Length == types.Length);

            var properties = names.Select((o, i) => new
            {
                Name = o,
                PropertyType = types[i]

            }).ToArray();

            var mb = GetAssemblyBuilder();

            //1、Create 类以及 ClassAttribute
            var random = new Random();
            var v1 = random.Next(1, 10000);
            var className = string.Format("<>AnonymousType_{0}_{1}", mb.GetTypes().Length, v1);//types.Count;


            var tb = mb.DefineType(className, TypeAttributes.Class | TypeAttributes.Public, typeof(object));
            var fields = new FieldBuilder[properties.Length];
            for (var i = 0; i < properties.Length; i++)// var property in properties)
            {
                var property = properties[i];
                var pb = tb.DefineProperty(property.Name, PropertyAttributes.HasDefault, property.PropertyType, Type.EmptyTypes);
                var ma = MethodAttributes.Public | MethodAttributes.Virtual;


                var f = tb.DefineField("<>" + property.Name, property.PropertyType, FieldAttributes.Private);


                var g = tb.DefineMethod("get_" + property.Name, ma, pb.PropertyType, Type.EmptyTypes);
                var gen = g.GetILGenerator();
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldfld, f);
                gen.Emit(OpCodes.Ret);
                pb.SetGetMethod(g);

                var s = tb.DefineMethod("set_" + property.Name, ma, null, new[] { pb.PropertyType });
                gen = s.GetILGenerator();
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Stfld, f);
                gen.Emit(OpCodes.Ret);
                pb.SetSetMethod(s);

                fields[i] = f;
            }

            //创建方法
            //var types = properties.Select(o => o.PropertyType).ToArray();
            var ctorBuilder = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, types);
            var genIL = ctorBuilder.GetILGenerator();
            //genIL.Emit(OpCodes.Ldarg_0);
            for (var i = 0; i < properties.Length; i++)
            {
                //var code = (OpCode)Enum.Parse(typeof(OpCodes), "Ldarg_" + (i + 1));
                var code = (OpCode)typeof(OpCodes).GetField("Ldarg_" + (i + 1)).GetValue(null);
                genIL.Emit(OpCodes.Ldarg_0);
                genIL.Emit(code);
                //genIL.Emit(code);
                genIL.Emit(OpCodes.Stfld, fields[i]);
            }
            genIL.Emit(OpCodes.Ret);


            var rowType = tb.CreateType();
#if DEBUG
            //var a = Activator.CreateInstance(rowType);
#endif
            return rowType;
        }

        ModuleBuilder GetAssemblyBuilder()
        {
            if (moduleBuilder == null)
            {
                AppDomain myCurrentDomain = AppDomain.CurrentDomain;
                AssemblyName myAssemblyName = new AssemblyName();
                var random = new Random();
                var v1 = random.Next(1, 10000);
                var v2 = random.Next(1, 10000);
                myAssemblyName.Name = "<>" + v1 + "_" + v2;
                var ab = myCurrentDomain.DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.Run);

                var modelName = "$" + myAssemblyName.Name;
                moduleBuilder = ab.DefineDynamicModule(modelName);
            }
            return moduleBuilder;
        }

        protected Expression ParseMultiSet()
        {
            //Debug.Assert(TokenIdentifierIs(KEYWORD_MULTISET));
            if (!TokenIdentifierIs(keywordMultiSet))
                throw ParseError(Res.TokenExpected, keywordMultiSet);

            NextToken();
            ValidateToken(TokenId.OpenParen);
            NextToken();

            var expr = ParseValue();
            var elementType = expr.Type;
            var items = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(elementType));
            items.Add(((ConstantExpression)expr).Value);

            while (token.Identity == TokenId.Comma)
            {
                NextToken();

                expr = ParseValue();
                if (expr.Type != elementType)
                    throw Errors.MultisetElemsAreNotTypeCompatible();

                var value = ((ConstantExpression)expr).Value;
                items.Add(value);
            }
            ValidateToken(TokenId.CloseParen, Res.CloseParenOrCommaExpected);
            NextToken();
            return Expression.Constant(items);
        }
    }
}